<?php

namespace api\oauth;

use api\oauth\exception\OauthException;
use EasyWeChat\Factory;

class WeChat
{
    public array $config;

    public function __construct($config = [])
    {
        $this->config = $config;

        $this->setConfig();
    }

    private function setConfig()
    {
        $defaultConfig = [
            'response_type' => 'array',
            'log' => [
                'level' => 'debug',
                'file' => app()->getRuntimePath() . 'wechat.log',
            ],
            'http' => [
                'verify' => false
            ],
            'verify' => false
        ];

        $this->config = array_merge($this->config, $defaultConfig);
    }

    /**
     * 获取用户信息（小程序）
     *
     * @param string $code 用户登录凭证（有效期五分钟）
     * @param string $iv 加密算法的初始向量
     * @param string $encryptedData 加密数据( encryptedData )
     * @return array
     * @throws OauthException
     */
    public function getUserInfoMini($code, $iv, $encryptedData)
    {
        try {
            $app = Factory::miniProgram($this->config);

            $res = $app->auth->session($code);
        } catch (\Exception $e) {
            exception_log('微信小程序登录失败', $e);
            throw new OauthException('授权失败' . $e->getMessage());
        }

        if ($res && !isset($res['errmsg'])) {
            $userInfo = $this->decodeMini($iv, $res['session_key'], $encryptedData);

            return array_merge($res, $userInfo);
        } else {
            throw new OauthException('授权失败: ' . $res['errmsg']);
        }
    }

    /**
     * code数据解析（小程序）
     *
     * @param string $code 用户登录凭证（有效期五分钟）
     * @return array
     * @throws OauthException
     */
    public function miniSessionDecode($code)
    {
        try {
            $app = Factory::miniProgram($this->config);

            $res = $app->auth->session($code);
        } catch (\Exception $e) {
            exception_log('微信小程序登录失败', $e);
            throw new OauthException('授权失败' . $e->getMessage());
        }
        if ($res && !isset($res['errmsg'])) {
            return $res;
        } else {
            throw new OauthException('授权失败: ' . $res['errmsg']);
        }
    }

    /**
     * 数据签名检验（小程序）
     *
     * @param string $iv 加密算法的初始向量
     * @param string $sessionKey session_key
     * @param string $encryptedData 加密数据( encryptedData )
     * @return array
     * @throws OauthException
     */
    public function decodeMini($iv, $sessionKey, $encryptedData)
    {
        try {
            $app = Factory::miniProgram($this->config);
            $weChatUserInfo = $app->encryptor->decryptData($sessionKey, $iv, $encryptedData);
        } catch (\Exception $e) {
            exception_log('微信小程序数据解析失败', $e);
            throw new OauthException('数据解析失败' . $e->getMessage());
        }

        return $weChatUserInfo;
    }


    /**
     * Oauth 授权跳转接口
     *
     * @param string $redirect_url 授权回跳地址
     * @param string $state 为重定向后会带上state参数（填写a-zA-Z0-9的参数值，最多128字节）
     * @param string $scope 授权类类型(可选值snsapi_base|snsapi_userinfo)
     * @return string
     */
    public function getOauthRedirect($redirect_url, $state = '', $scope = 'snsapi_base')
    {
        $app = Factory::officialAccount($this->config);

        return $app->oauth->scopes([$scope])->redirect($redirect_url);
    }

    /**
     * 获取已授权用户信息
     *
     * @param $code
     * @return array
     */
    public function getOauthAccessToken($code = '')
    {
        $app = Factory::officialAccount($this->config);

        return $app->oauth->userFromCode($code);
    }
}
